#include <iostream>
#include <thread>
#include <csignal>
#include <cstdlib>
#include <vector>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include "mqttclient/mqttclient.h"
#include "httplib/httplib.h"
#include "websocketclient/easywsclient.hpp"
#include "msgqueue_util/msgqueue_util.h"
#include "fifo_util/fifo_util.h"
#include "sqlite3helper/sqlite3helper.h"
#include "jsonbean/jsonbean.h"
#include "rapidjson_util/rapidjson_util.h"

#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h"

#include "diskinfo/diskinfo.h"
#include "netinterfaceinfo/netinterfaceinfo.h"

#include "fileutil/fileutil.h"
#include "xmlhelper/xmlhelper.h"

#include "commlog_def.h"

#ifdef _WIN32
#pragma comment(lib, "ws2_32")
#include <WinSock2.h>
#endif


void pfnRecvMQTTMsgCallback(void *pCtx, const MqttMessageInfo& stMqMsgInfo)
{
    (void)pCtx;
    std::cout << ">>> "<< stMqMsgInfo.stTopicInfo.strTopic << " recv data len: " << stMqMsgInfo.strData.size()<< std::endl;
    std::cout << ">>> data is: " << stMqMsgInfo.strData << std::endl;

    return;
}

void testMqttClient()
{
    initMqttLibrary();

    MqttConnectInfo stConInfo;
    stConInfo.bAnonymous = false;
    stConInfo.strAccount = "shelman";
    stConInfo.strPwd = "abc123";
    stConInfo.strBrokerIp = "192.168.154.128";
    stConInfo.ui16BrokerPort = 1883;

    std::vector<MqttTopicInfo> vtTopics;

    MqttTopicInfo stTopicInfo;
    stTopicInfo.iQOS = TOPIC_QOS_MOSTONCE;
    stTopicInfo.strTopic = "channel/test/topic01";
    vtTopics.push_back(stTopicInfo);

    stTopicInfo.strTopic = "channel/test/topic02";
    vtTopics.push_back(stTopicInfo);

    vtTopics.emplace_back(MqttTopicInfo("channel/test/topic03", TOPIC_QOS_ONLYONCE));

    MqttClient client(stConInfo);
    client.connect(vtTopics, pfnRecvMQTTMsgCallback);

    for (int i = 0; i < 30; ++i) {

        MqttMessageInfo stMqMsgInfo;
        stMqMsgInfo.stTopicInfo.iQOS = 2;
        stMqMsgInfo.stTopicInfo.strTopic = "channel/test/topic03";
        stMqMsgInfo.strData = "abc1234567890";
        client.publish(stMqMsgInfo);
        printf("<<< publish data: %s.\r\n", stMqMsgInfo.stTopicInfo.strTopic.data());
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }

    getchar();
    client.disconnect();
    deinitMqttLibrary();

    return;
}

static int gs_iPort = 58080;
void testHttp(int argc, char **argv)
{
    if (3 > argc) {
        return;
    }

    // R"(string)"表示不需要对string中的特殊字符进行转义
    if (0 == strcmp(argv[2], "server")) {
        // 作为服务端
        std::cout << "Start http server..." << std::endl;
        httplib::Server svr;
        svr.set_error_handler([](const httplib::Request &req, httplib::Response &res) {
            std::cerr << "Server-error:" << req.method << "\t" << req.path << "\tstatus:" << res.status << std::endl;
            std::string json = R"({\"message\": \"path error\"})";
            res.set_content(json, "text/plain");
        }); // 路由处理抛了异常，会被捕获，然后进入set_error_handler逻辑


        svr.Get("/hello", [](const httplib::Request &req, httplib::Response &res) {
            std::cout << "Server-log:" << req.method << "\t" << req.path << "\t" << req.body << std::endl;
            // 获取 url 中的参数
            for (auto it = req.params.begin(); it != req.params.end(); ++it) {
                std::cout << ">>>>" << it->first << ": " << it->second << std::endl;
            }

            res.set_content(R"({"message": "get request", "status": "200 OK"})", "appliation/json");
        });

        svr.Post("/hello", [](const httplib::Request &req, httplib::Response &res) {
            std::cout << "Server-log:" << req.method << "\t" << req.path << "\t" << req.body << std::endl;
            res.set_content(R"({"message": "post request", "status": "200 OK"})", "appliation/json");
        });

        svr.listen(/*"192.168.154.128"*/"localhost", gs_iPort);
    } else if (0 == strcmp(argv[2], "client")) {
        // 作为客户端
        httplib::Client cli(/*"192.168.154.128"*/"localhost", gs_iPort);
        auto res = cli.Post("/hello", R"({"user": "shelman", "pwd":"your0123456"})", "application/json");
        if (res) {
            std::cout << "Status Code:" << res->status << std::endl;
            std::cout << "Header:\n";
            for (auto it = res->headers.begin(); it != res->headers.end(); ++it) {
                std::cout << ">>>>" << it->first << ": " << it->second << std::endl;
            }
            std::cout << "Body:\n" << res->body << std::endl;
        }

        res = cli.Get("/hello");
        if (res) {
            std::cout << "Status Code:" << res->status << std::endl;
            std::cout << "Header:\n";
            for (auto it = res->headers.begin(); it != res->headers.end(); ++it) {
                std::cout << ">>>>" << it->first << ": " << it->second << std::endl;
            }
            std::cout << "Body:\n" << res->body << std::endl;
        }
    } else {
        std::cerr << ">>> input wrong params." << std::endl;
    }

    return;
}

using easywsclient::WebSocket;
static WebSocket::pointer g_wsPCClient = nullptr;
static WebSocket::pointer g_wsIMUClient = nullptr;
static volatile bool gs_bStatus = true;

static void pfnSigExit(int signum)
{
    std::signal(signum, SIG_DFL); // 还原默认的信号处理
    gs_bStatus = false;
    return;
}

static void pfnOnHandlePCWSMessage(const std::string& message)
{
    printf(">>> receive point cloud message size: %ld.\r\n", message.size());
    return;
}

static void pfnOnHandleIMUWSMessage(const std::string& message) {
    printf(">>> receive IMU message size: %ld.\r\n", message.size());
    return;
}

void testWebsocketClient()
{
    std::signal(SIGINT, pfnSigExit);
    std::signal(SIGTERM, pfnSigExit);
    std::signal(SIGABRT, pfnSigExit);
    std::signal(SIGSEGV, pfnSigExit);

#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
    WSADATA wsaData;
    if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) {
        printf("WSAStartup Failed.\n");
        return;
    }
#endif
    //std::thread thPointCloud(pfnGeneratePointCloudData, std::ref(m_bRunning));
    std::thread thPointCloud([](){
        g_wsPCClient = WebSocket::from_url("ws://172.18.56.205:58088/v1/livox_mid360/point_cloud/display");
        if (g_wsPCClient && (g_wsPCClient->getReadyState() == WebSocket::OPEN)) {
            g_wsPCClient->send("Hello");
            g_wsPCClient->poll(10); // 这个必须要调用，否则不能发送，发送跟接收都是异步的，都是在这个poll函数里监测处理的

            //g_wsPCClient->dispatch(pfnOnHandlePCWSMessage);
#if 1
            while (gs_bStatus && g_wsPCClient->getReadyState() == WebSocket::OPEN/*g_wsPCClient->getReadyState() != WebSocket::CLOSED*/) {
                g_wsPCClient->poll(); // 检查是否有新消息
                g_wsPCClient->dispatch(pfnOnHandlePCWSMessage);
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
#endif
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

            g_wsPCClient->close();
            delete g_wsPCClient;
            g_wsPCClient = nullptr;
        }
    });
    thPointCloud.detach();

    //std::thread thIMU(pfnGenerateIMUData, std::ref(m_bRunning));
    std::thread thIMU([](){
        g_wsIMUClient = WebSocket::from_url("ws://172.18.56.205:58088/v1/livox_mid360/imu/display");
        if (g_wsIMUClient && (g_wsIMUClient->getReadyState() == WebSocket::OPEN)) {
            g_wsIMUClient->send("Hello");
            g_wsIMUClient->poll(10); // 这个必须要调用，否则不能发送，发送跟接收都是异步的，都是在这个poll函数里监测处理的

            //g_wsIMUClient->dispatch(pfnOnHandleIMUWSMessage);
#if 1
            while (gs_bStatus && g_wsIMUClient->getReadyState() == WebSocket::OPEN/*g_wsIMUClient->getReadyState() != WebSocket::CLOSED*/) {
                g_wsIMUClient->poll(); // 检查是否有新消息
                g_wsIMUClient->dispatch(pfnOnHandleIMUWSMessage);
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
#endif
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

            g_wsIMUClient->close();
            delete g_wsIMUClient;
            g_wsIMUClient = nullptr;
        }
    });
    thIMU.detach();

    while (gs_bStatus)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
    }

#ifdef defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
    WSACleanup();
#endif

    return;
}

#define MQ_CREATE_BY_KEY_ONLY 1
#define ASEND_BRECV 0

void testMessageQueue(int argc, char **argv)
{
    if (3 > argc) {
        return;
    }

    std::signal(SIGINT, pfnSigExit);
    int iMsgID = -1;
#if (0 == MQ_CREATE_BY_KEY_ONLY)
#ifdef __linux__
    const char* pMQPath = "/home/shelman/Share/msgqueue_test.txt";
#else
    const char* pMQPath = "D:\\msgqueue_test.txt";
#endif
#endif
    int iProjId = 0x0002;
    if (0 == strcmp(argv[2], "A")) {
        printf("create and open message queue succeed.\r\n");
#if MQ_CREATE_BY_KEY_ONLY
        iMsgID = msgqueue_create_and_open_by_key(iProjId);
#else
        iMsgID = msgqueue_create_and_open(pMQPath, iProjId);
#endif
        if (0 <= iMsgID) {
            while (gs_bStatus) {
#if ASEND_BRECV
                char szData[32] = "this is A test message.";
                msgqueue_write(iMsgID, szData, strlen(szData));
#else
                char szRecv[32] = {0};
                int iLen = msgqueue_read(iMsgID, szRecv, sizeof (szRecv));
                if (0 < iLen) {
                    printf(">>> receive msg: %s.\r\n", szRecv);
                }
#endif
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }
        } else {
            printf("create and open message queue failed, msgid: %d.\r\n", iMsgID);
        }
    } else {
        printf("open message queue succeed.\r\n");
#if MQ_CREATE_BY_KEY_ONLY
        iMsgID = msgqueue_open_by_key(iProjId);
#else
        iMsgID = msgqueue_open(pMQPath, iProjId);
#endif
        if (0 <= iMsgID) {
#if ASEND_BRECV
            msgqueue_set_readdata_callback([](int fd, void* buffer, size_t size, void *context) {
                (void)context;
                printf(">>> [%d] receive len: %ld, msg: %s.\r\n", fd, size, buffer);
                return;
            }, nullptr);

            msgqueue_loop_start();

            while (gs_bStatus) {
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }
            msgqueue_loop_stop();
#else
            while (gs_bStatus) {
                char szData[32] = {0};
                sprintf(szData, "this is %s feedback message.", argv[2]);
                msgqueue_write(iMsgID, szData, strlen(szData));
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }
#endif
        } else {
            printf("open message queue failed, msgid: %d.\r\n", iMsgID);
        }
    }

    if (0 <= iMsgID) {
        if (0 == strcmp(argv[2], "A")) {
            msgqueue_close_and_destroy(iMsgID);
        } else {
            msgqueue_close(iMsgID);
        }
    }

    return;
}

void testFIFO(int argc, char **argv)
{
    if (3 > argc) {
        return;
    }

    printf("test fifo util.\r\n");

    std::signal(SIGINT, pfnSigExit);
    //std::signal(SIGPIPE, SIG_IGN); // 忽略SIGPIPE信号，避免读端关闭后导致写端退出
#if defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64)
    const char* pfifo = "test_fifo";
    int fd = -1;
    if (0 == strcmp(argv[2], "A")) {
        fd = fifoutil_open(pfifo, FIFO_SERVER);
        if (0 <= fd) {
            printf("open fifo succeed.\r\n");
            //fifoutil_set_nonblocking(fd); 作为服务端，不能设置为非阻塞模式
            fifoutil_set_readdata_callback([](int fd, void* buffer, size_t size, void *context) {
                (void)context;
                printf(">>> [%d] receive len: %ld, msg: %s.\r\n", fd, size, buffer);
                return;
            }, nullptr);

            fifoutil_loop_start(fd, FIFO_SERVER);
            while (gs_bStatus) {
                //char szData[32] = {0};
                //fifoutil_read(fd, szData, sizeof (szData));
                //printf(">>> A recv fifo data: %s.\r\n", szData);
                char szData[32] = "this is A fifo message.";
                fifoutil_write(fd, szData, strlen(szData));
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }
            fifoutil_loop_stop();
        } else {
            printf("open fifo failed.\r\n");
        }
    } else {

        // 每次打开管道发送数据后进行关闭
        fd = fifoutil_open(pfifo, FIFO_CLIENT);
        if (0 <= fd) {
            printf("open fifo succeed.\r\n");
            fifoutil_set_nonblocking(fd);
            fifoutil_set_readdata_callback([](int fd, void* buffer, size_t size, void *context) {
                (void)context;
                printf(">>> [%d] receive len: %ld, msg: %s.\r\n", fd, size, buffer);
                return;
            }, nullptr);

            fifoutil_loop_start(fd, FIFO_CLIENT);

            while (gs_bStatus) {
                char szData[64] = {0};
                sprintf(szData, "this is %s fifo message.", argv[2]);
                fifoutil_write(fd, szData, strlen(szData));
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }

            fifoutil_loop_stop();
            fifoutil_close(fd);
        } else {
            printf("open fifo failed.\r\n");
        }

    }

    if (0 <= fd) {
        fifoutil_close(fd);
        fd = -1;
    }
#else
#ifdef __linux__
    const char* pfifo = "/home/shelman/Share/fifo.txt"; // 文件路径需要存在
#else
    const char* pfifo = "D:\\fifo.txt"; // 文件路径需要存在
#endif
    int fd = -1;

    if (0 == strcmp(argv[2], "A")) {
        if (0 == fifoutil_create(pfifo)) {
#if ASEND_BRECV
            fd = fifoutil_open(pfifo, O_WRONLY); // 创建端只读时如果使用O_NONBLOCK模式，必须等对端打开才生效，因此使用阻塞模式
            fifoutil_set_nonblocking(fd);
#else
            fd = fifoutil_open(pfifo, O_RDONLY | O_NONBLOCK);
#endif
            if (0 <= fd) {
                printf("open fifo succeed.\r\n");
#if ASEND_BRECV
                while (gs_bStatus) {
                    char szData[32] = "this is A fifo message.";
                    fifoutil_write(fd, szData, strlen(szData));
                    std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
                }
#else
                fifoutil_set_readdata_callback([](int fd, void* buffer, size_t size, void *context) {
                    (void)context;
                    printf(">>> [%d] receive len: %ld, msg: %s.\r\n", fd, size, buffer);
                    return;
                }, nullptr);

                fifoutil_loop_start(fd, 0);
                while (gs_bStatus) {
                    std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
                }
                fifoutil_loop_stop();
#endif
            } else {
                printf("open fifo failed.\r\n");
            }
        } else {
            printf("create fifo failed.\r\n");
        }
    } else {
#if ASEND_BRECV
        fd = fifoutil_open(pfifo, O_RDONLY | O_NONBLOCK);
        fifoutil_set_nonblocking(fd);
#else
        fd = fifoutil_open(pfifo, O_WRONLY | O_NONBLOCK);
#endif
        if (0 <= fd) {
            printf("open fifo succeed.\r\n");
            while (gs_bStatus) {
#if ASEND_BRECV
                char szData[32] = {0};
                fifoutil_read(fd, szData, sizeof (szData));
                printf(">>> B recv fifo data: %s.\r\n", szData);
#else
                char szData[32] = {0};
                sprintf(szData, "this is %s fifo message.", argv[2]);
                fifoutil_write(fd, szData, strlen(szData));
#endif
                std::this_thread::sleep_for(std::chrono::seconds(1)); // 切换CPU时间
            }
        } else {
            printf("open fifo failed.\r\n");
        }
    }

    if (0 <= fd) {
        fifoutil_close(fd);
        fd = -1;
    }

    if (0 == strcmp(argv[2], "A")) {
        fifoutil_destroy(pfifo);
    }
#endif
    return;
}

void testSqlite3_0()
{
    std::cout << "test sqlite" << std::endl;
#ifdef __linux__
    std::string strDbName = "./db/test.db"; // db的目录需要先存在
#else
    std::string strDbName = "test.db";
#endif

    Sqlite3Helper helper;
    //helper.createOrOpenDatabase(strDbName);
    bool bRet = helper.createOrOpenDatabase(strDbName);
    if (bRet) {
        std::string strTbName = "student";
        std::string strExp = "name varchar(32) primary key not null, score real, class varchar(32) not null";

        if (helper.createTable(strTbName, strExp)) {
            //helper.clearRecords(strTbName);

            std::vector<std::string> vtNames;
            vtNames.emplace_back("name");
            vtNames.emplace_back("score");
            vtNames.emplace_back("class");

            std::vector<std::string> vtValues;
            vtValues.emplace_back("zhang san");
            vtValues.emplace_back("98.64");
            vtValues.emplace_back("class 1");
            helper.insert(strTbName, vtNames, vtValues);

            vtValues.clear();
            vtValues.emplace_back("li si");
            vtValues.emplace_back("61.05");
            vtValues.emplace_back("class 2");
            helper.insert(strTbName, vtNames, vtValues);

            vtValues.clear();
            vtValues.emplace_back("wang wu");
            vtValues.emplace_back("81.75");
            vtValues.emplace_back("class 3");
            helper.insert(strTbName, vtNames, vtValues);

            vtValues.clear();
            vtValues.emplace_back("qian liu");
            vtValues.emplace_back("71.41");
            vtValues.emplace_back("class 4");
            helper.insert(strTbName, vtNames, vtValues);

            vtValues.clear();
            vtValues.emplace_back("tian qi");
            vtValues.emplace_back("86.29");
            vtValues.emplace_back("class 5");
            helper.insert(strTbName, vtNames, vtValues);

            size_t iRowCnt = helper.getRowCount(strTbName);
            printf("there are %d records in table %s.\r\n", iRowCnt, strTbName.data());

            vtValues.clear();
            iRowCnt = helper.getValues(strTbName, "", 3, vtValues);
            size_t iIndex = 0;
            for (size_t i = 0, iSize = vtValues.size(); i < iRowCnt && iIndex < iSize; ++i) {
                printf("table content: %s, %s, %s.\r\n", vtValues[iIndex++].data(), vtValues[iIndex++].data(), vtValues[iIndex++].data());
                //std::cout << vtValues[iIndex++] << ", " << vtValues[iIndex++] << ", " << vtValues[iIndex++] << std::endl;
            }

            vtNames.clear();
            vtNames.emplace_back("score");
            vtNames.emplace_back("class");
            vtValues.clear();
            vtValues.emplace_back("91.36");
            vtValues.emplace_back("class 4");

            helper.update(strTbName, vtNames, vtValues, "name = 'li si'");

#ifdef __linux__
            std::string strBackupDbName = "./db/testbackup.db"; // db的目录需要先存在
#else
            std::string strBackupDbName = "testbackup.db";
#endif
            helper.backup(strBackupDbName);

            printf("update table.\r\n");
            vtValues.clear();
            iRowCnt = helper.getValues(strTbName, "", 3, vtValues);
            iIndex = 0;
            for (size_t i = 0, iSize = vtValues.size(); i < iRowCnt && iIndex < iSize; ++i)
            {
                printf("table content: %s, %s, %s.\r\n", vtValues[iIndex++].data(), vtValues[iIndex++].data(), vtValues[iIndex++].data());
                //std::cout << vtValues[iIndex++] << ", " << vtValues[iIndex++] << ", " << vtValues[iIndex++] << std::endl;
            }

            //helper.deleteRecord(strTbName, "name = 'tian qi'");
            //helper.deleteRecord("student", "class = 'class 3'");

        } else {
            printf("create table %s failed.\r\n", strTbName.data());
        }

        helper.closeDatabase();
        //helper.dropDatabase(strDbName);
    } else {
        printf("create or open %s database failed.\r\n", strDbName.data());
    }

    return;
}

void testSqlite3_1()
{
    std::cout << "test sqlite query" << std::endl;
    std::string strDbName = "test.db";

    Sqlite3Helper helper;
    if (helper.createOrOpenDatabase(strDbName)) {
        std::string strTbName = "student_new";
        std::string strExp = "name text primary key not null, age integer, class varchar(16) not null, score real";

        if (helper.createTable(strTbName, strExp)) {
            helper.clearRecords(strTbName);

            std::vector<std::string> vtNames;
            vtNames.emplace_back("name");
            vtNames.emplace_back("age");
            vtNames.emplace_back("class");
            vtNames.emplace_back("score");

            std::vector<std::string> vtValues0 = {"sun yi", "12", "class 1", "88.04"};
            helper.insert(strTbName, vtNames, vtValues0);

            std::vector<std::string> vtValues1 = {"qian er", "14", "class 1", "98.38"};
            helper.insert(strTbName, vtNames, vtValues1);

            std::vector<std::string> vtValues2 = {"zhang san", "13", "class 1", "96.74"};
            //vtValues2.emplace_back("zhang san");
            //vtValues2.emplace_back("13");
            //vtValues2.emplace_back("class 1");
            //vtValues2.emplace_back("96.74");
            helper.insert(strTbName, vtNames, vtValues2);

            std::vector<std::string> vtValues3 = {"li si", "11", "class 1", "91.54"};
            helper.insert(strTbName, vtNames, vtValues3);

            std::vector<std::string> vtValues4 = {"wang wu", "12", "class 1", "94.88"};
            helper.insert(strTbName, vtNames, vtValues4);

            std::vector<std::string> vtValues5 = {"zhao liu", "13", "class 1", "99.88"};
            helper.insert(strTbName, vtNames, vtValues5);

            std::vector<std::string> vtValues6 = {"tian qi", "15", "class 1", "95.62"};
            helper.insert(strTbName, vtNames, vtValues6);

            std::vector<std::string> vtValues7 = {"zhou ba", "14", "class 1", "96.83"};
            helper.insert(strTbName, vtNames, vtValues7);

            std::vector<std::string> vtValues8 = {"wu jiu", "14", "class 2", "96.83"};
            helper.insert(strTbName, vtNames, vtValues8);

            int iRowCnt = helper.getRowCount(strTbName);
            printf("there are %d records in table %s.\r\n", iRowCnt, strTbName.data());

            std::cout << "---------------------" << std::endl;
            size_t iRows = 0, iColumn = 4;
            std::vector<std::string> vtResults;
            //std::string strStatement = "select * from " + strTbName + ";";
            std::string strStatement = "select * from " + strTbName + " where class = 'class 1';";
            iRows = helper.getValuesByStatement(strStatement, iColumn, vtResults);
            //std::cout << "rows: " << iRows << ", total: " <<  vtResults.size() << " - " << (iRows * iColumn) << std::endl;
            if (vtResults.size() >= (iRows * iColumn)) {
                for (size_t i = 0; i < iRows; ++i) {
                    for (size_t j = 0; j < iColumn; ++j) {
                        std::cout << vtResults[i * iColumn + j] << " || ";
                    }
                    std::cout << std::endl;
                }
            }

            std::cout << "---------------------" << std::endl;
            vtResults.clear();
            strStatement = "select * from " + strTbName + " where class = 'class 2';";
            iRows = helper.getValuesByStatement(strStatement, iColumn, vtResults);
            if (vtResults.size() >= (iRows * iColumn)) {
                for (size_t i = 0; i < iRows; ++i) {
                    for (size_t j = 0; j < iColumn; ++j) {
                        std::cout << vtResults[i * iColumn + j] << " || ";
                    }
                    std::cout << std::endl;
                }
            }

            std::cout << "---------------------" << std::endl;
            vtResults.clear();
            iColumn = 2;
            strStatement = "select name, score from " + strTbName + ";";
            iRows = helper.getValuesByStatement(strStatement, iColumn, vtResults);
            if (vtResults.size() >= (iRows * iColumn)) {
                for (size_t i = 0; i < iRows; ++i) {
                    for (size_t j = 0; j < iColumn; ++j) {
                        std::cout << vtResults[i * iColumn + j] << " || ";
                    }
                    std::cout << std::endl;
                }
            }

            std::cout << "---------------------" << std::endl;
            vtResults.clear();
#if 0
            iColumn = 4;
            strStatement = "select name, age, class, score from " + strTbName + " where class = 'class 1' order by age desc;"; // 升序：asc，降序：desc
#else
            iColumn = 3;
            strStatement = "select name, class, score from " + strTbName + " order by age asc;"; // 升序：asc，降序：desc
#endif
            iRows = helper.getValuesByStatement(strStatement, iColumn, vtResults);
            if (vtResults.size() >= (iRows * iColumn)) {
                for (size_t i = 0; i < iRows; ++i) {
                    for (size_t j = 0; j < iColumn; ++j) {
                        std::cout << vtResults[i * iColumn + j] << " || ";
                    }
                    std::cout << std::endl;
                }
            }

        } else {
            printf("create table %s failed.\r\n", strTbName.data());
        }

        helper.closeDatabase();
    } else {
        printf("create or open %s database failed.\r\n", strDbName.data());
    }

    return;
}

void testSqlite3()
{
    testSqlite3_0();
    std::cout << "---------------------" << std::endl;
    testSqlite3_1();
    return;
}

void testjson()
{
    JsonBean obj;
    obj.add("status", 200);
    obj.add("value", 12.6);
    obj.add("message", "this message");

    JsonBean objData;
    objData.add("file", "./db/test.db");

    JsonBean objArrayJson(JsonBean::Array);
    for(int i = 0; i < 3; ++i)
    {
        JsonBean itemJson;
        itemJson.add("key1", 123);
        itemJson.add("key2", 45.6);
        itemJson.add("key3", "message");
        objArrayJson.addDataToArray(itemJson);
    }
    objData.add("objArr", objArrayJson);

    JsonBean objIntArray(JsonBean::Array);
    for(int i = 0; i < 10; ++i)
    {
        objIntArray.addDataToArray(123);
    }

    objData.add("intArr", objIntArray);

    obj.add("data", objData);
    printf("json info: %s.\r\n", obj.unformattedData().data());

    std::string strJosnInfo = "{\"key1\":\"message\", \"doubleValue\": 123.783, \"obj\": {\"key2\":456, \"key3\": 156.8}, \"status\": 200}";
    JsonBean objParse(strJosnInfo);
    if (objParse.isJsonOk()) {
        printf("key1: %s.\r\n", objParse.value("key1").toString().data());
        printf("doubleValue: %f.\r\n", objParse.value("doubleValue").toDouble());
        printf("status: %d.\r\n", objParse.value("status").toInt());

        JsonBean obj = objParse.value("obj");
        printf("key3: %f.\r\n", obj.value("key3").toDouble());
        printf("key2: %d.\r\n", obj.value("key2").toInt());
    }

    const char* const topic = "/v1/endpoint_ess/%s/status/report";
    char szTopic[64] = {0};
    snprintf(szTopic, sizeof (szTopic), topic, "pml_sn_001-235");
    printf("total topic: %s.\r\n", szTopic);

    std::cout << "-----------------" << std::endl;
    JsonBean objNew;
    objNew.add("name", "zhaoliu");

    std::vector<std::string> vtStrs;
    vtStrs.emplace_back("12345");
    vtStrs.emplace_back("22345");
    objNew.addStringArray("strarr", vtStrs, JsonBean::NA);

    std::vector<double> vtDous;
    vtDous.emplace_back(123.45);
    vtDous.emplace_back(22.345);
    objNew.addDoubleArray("douarr", vtDous);

    JsonBean objArr(JsonBean::Array);
    std::vector<int> vtIns = {12, 4, 67, 88, 90, 234};
    objArr.addArray(vtIns);

    JsonBean objArrb(JsonBean::Array);
    std::vector<bool> vtBos = {false, false, true};
    objArrb.addArray(vtBos);

    objNew.add("arrs", objArr);
    objNew.add("arrsb", objArrb);

    std::cout << objNew.unformattedData() << std::endl;
    std::cout << "-----------------" << std::endl;

    std::string strJson = R"({"name":"Alice","age":32,"enable":true,"hight":156.78,"state":[true,false,true,false,false],"data":{"message":"this is message","status":200},"hobbies":["reading","coding","traveling"],"objs":[{"int":12,"ddd":234.56},{"int":24,"ddd":678.56}],"scorse":[23.4,56.7,89.8,45.5]})";
    JsonBean util(strJson);
    if (util.isJsonOk()) {
        printf("name: %s, age: %d, enable: %d, hight: %f.\r\n"
               , util.value("name").toString().c_str(), util.value("age").toInt()
               , util.value("enable").toBool(), util.value("hight").toDouble());

        std::cout << util.getString("data") << std::endl;

        JsonBean utildata = util.value("data");
        std::cout << utildata.getString("message") << ", " << utildata.getInt("status") << std::endl;
        std::cout << util.getString("objs") << std::endl;

        std::vector<std::string> vtStrings;
        util.getStringArray("hobbies", vtStrings);
        for (size_t i = 0, size = vtStrings.size(); i < size; ++i) {
            printf("item: %lu, value: %s.\r\n", i, vtStrings[i].c_str());
        }

        std::vector<JsonBean> vtObjs;
        util.getObjArray("objs", vtObjs);
        for (size_t i = 0, size = vtObjs.size(); i < size; ++i) {
            printf("item: %lu, value: %s.\r\n", i, vtObjs[i].unformattedData().c_str());
        }

        std::vector<double> vtDVals;
        util.getDoubleArray("scorse", vtDVals);
        for (size_t i = 0, size = vtDVals.size(); i < size; ++i) {
            printf("item: %lu, value: %f.\r\n", i, vtDVals[i]);
        }

        std::cout << "-----------------" << std::endl;
        std::cout << util.getString("state") << std::endl;
        std::vector<bool> vtBools;
        util.getBoolArray("state", vtBools);
        for (size_t i = 0, size = vtBools.size(); i < size; ++i) {
            printf("item: %lu, value: %d.\r\n", i, static_cast<int>(vtBools[i]));
        }
    }

    return;
}

void testRapidJosnWriter()
{
    // 创建一个新的 JSON 对象
    rapidjson::Document doc;
    doc.SetObject();

    // 添加键值对
    rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
    doc.AddMember("name", "Bob", allocator);
    doc.AddMember("age", 25, allocator);

    // 添加数组
    rapidjson::Value hobbies(rapidjson::kArrayType);
    hobbies.PushBack("gaming", allocator);
    hobbies.PushBack("music", allocator);
    doc.AddMember("hobbies", hobbies, allocator);

    // 添加数组
    rapidjson::Value dhobbies(rapidjson::kArrayType);
    dhobbies.PushBack(12.5, allocator);
    dhobbies.PushBack(88.5, allocator);
    doc.AddMember("dhobbies", dhobbies, allocator);

    // 添加数组
    rapidjson::Value objhobbies(rapidjson::kArrayType);
    // 构造第一个对象
    rapidjson::Value obj1;
    obj1.SetObject();
    obj1.AddMember("name", "Alice", allocator);
    obj1.AddMember("age", 30, allocator);
    obj1.AddMember("city", "New York", allocator);

    // 构造第二个对象
    rapidjson::Value obj2;
    obj2.SetObject();
    obj2.AddMember("name", "Bob", allocator);
    obj2.AddMember("age", 25, allocator);
    obj2.AddMember("city", "Los Angeles", allocator);

    // 将对象添加到数组中
    objhobbies.PushBack(obj1, allocator);
    objhobbies.PushBack(obj2, allocator);

    doc.AddMember("objhobbies", objhobbies, allocator);

    // 序列化为 JSON 字符串
    rapidjson::StringBuffer buffer;
    rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
    doc.Accept(writer);

    std::cout << "Generated JSON:\n" << buffer.GetString() << std::endl;
    return;
}

void testRapidJosnReader()
{
    const char* json = R"({"name":"Alice","age":30,"hobbies":["reading","coding","traveling"]})";
    rapidjson::Document doc;
    doc.Parse(json);

    if (doc.HasParseError()) {
        std::cerr << "JSON parse error" << std::endl;
        return;
    }

    // 使用 Value 访问解析后的数据
    if (doc.HasMember("name") && doc["name"].IsString()) {
        std::cout << "Name: " << doc["name"].GetString() << std::endl;
    }

    if (doc.HasMember("age") && doc["age"].IsInt()) {
        std::cout << "Age: " << doc["age"].GetInt() << std::endl;
    }

    if (doc.HasMember("hobbies") && doc["hobbies"].IsArray()) {
        const rapidjson::Value& hobbies = doc["hobbies"];
        for (const auto& hobby : hobbies.GetArray()) {
            if (hobby.IsString()) {
                std::cout << "Hobby: " << hobby.GetString() << std::endl;
            }
        }
    }

    return;
}

void testPackgeOrParse()
{
    std::vector<RapidJsonInfo> vtPkgJsonInfos;
    RapidJsonInfo stJsonInfo;
    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_INT32;
    stJsonInfo.strKey = "intVal";
    stJsonInfo.iVal = 123;
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_STRING;
    stJsonInfo.strKey = "strVal";
    stJsonInfo.strVal = "string";
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_UINT32;
    stJsonInfo.strKey = "uiVal";
    stJsonInfo.uiVal = 255;
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_DOUBLE;
    stJsonInfo.strKey = "doubleVal";
    stJsonInfo.dVal = 25.56;
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_BOOL;
    stJsonInfo.strKey = "boolVal";
    stJsonInfo.bVal = false;
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_OBJ;
    stJsonInfo.strKey = "objVal";
    stJsonInfo.strVal = R"({"name":"Alice","NULL":null,"arr":[1,2,3,4], "objs":[{"int":12,"ddd":234.56},{"int":24,"ddd":678.56}]})";
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    stJsonInfo.emDataType = RapidJsonDataType::RPJDT_ARR;
    stJsonInfo.strKey = "arrVal";
    stJsonInfo.strVal = R"([4.89,9.087,79.55,23.76,87.67])";
    vtPkgJsonInfos.emplace_back(stJsonInfo);

    printf("json: %s.\r\n", packageAllJsonInfoByRapid(vtPkgJsonInfos).c_str());

    const char* json = R"({"name":"Alice","age":32,"enable":true,"hight":156.78,"data":{"message":"this is message","status":200},"objs":[{"int":12,"ddd":234.56},{"int":24,"ddd":678.56}],"hobbies":["reading","coding","traveling"],"scorse":[23.4,56.7,89.8,45.5]})";
    std::vector<RapidJsonInfo> vtJsonInfos;
    parseAllJsonInfoByRapid(json, vtJsonInfos);
    for (size_t i = 0, size = vtJsonInfos.size(); i < size; ++i) {
        const RapidJsonInfo& jsonInfo = vtJsonInfos[i];
        if (RapidJsonDataType::RPJDT_INT32 == jsonInfo.emDataType) {
            printf("key: %s, value: %d.\r\n", jsonInfo.strKey.c_str(), jsonInfo.iVal);
        } else if (RapidJsonDataType::RPJDT_UINT32 == jsonInfo.emDataType) {
            printf("key: %s, value: %d.\r\n", jsonInfo.strKey.c_str(), jsonInfo.uiVal);
        } else if (RapidJsonDataType::RPJDT_DOUBLE == jsonInfo.emDataType) {
            printf("key: %s, value: %f.\r\n", jsonInfo.strKey.c_str(), jsonInfo.dVal);
        } else if (RapidJsonDataType::RPJDT_BOOL == jsonInfo.emDataType) {
            printf("key: %s, value: %d.\r\n", jsonInfo.strKey.c_str(), jsonInfo.bVal);
        } else if (RapidJsonDataType::RPJDT_STRING == jsonInfo.emDataType) {
            printf("key: %s, value: %s.\r\n", jsonInfo.strKey.c_str(), jsonInfo.strVal.c_str());
        } else if (RapidJsonDataType::RPJDT_OBJ == jsonInfo.emDataType
                   || RapidJsonDataType::RPJDT_ARR == jsonInfo.emDataType) {
            printf("key: %s, value: %s.\r\n", jsonInfo.strKey.c_str(), jsonInfo.strVal.c_str());
        } else {
            // TODO
        }
    }

    return;
}

void testRapidJsonPackage()
{
    RapidJsonUtil util;
    util.add("name", std::string("li si"));
    util.add("age", 35);
    util.add("weight", 75.68);
    util.add("gender", std::string("boy"));
    util.add("message", "this is message");
    util.add("girl", false);
    std::cout << "package json 0: " << util.unformattedData() << std::endl;
    std::vector<std::string> vtClass;
    vtClass.emplace_back("english");
    vtClass.emplace_back("chiness");
    vtClass.emplace_back("math");
    vtClass.emplace_back("physical");
    util.addStringArray("class", vtClass, RapidJsonUtil::NA);
    std::cout << "------------------" << std::endl;
    std::cout << "package json 1: " << util.unformattedData() << std::endl;
    RapidJsonUtil data;
    data.add("play", std::string("school"));
    data.add("time", std::string("today"));
    util.add("other", data);
    std::cout << "------------------" << std::endl;
    std::cout << "package json 2: " << util.unformattedData() << std::endl;
    RapidJsonUtil arr(RapidJsonUtil::Array);
    arr.addDataToArray(23.89);
    arr.addDataToArray(53.89);
    arr.addDataToArray(23.99);
    arr.addDataToArray(83.89);
    arr.addDataToArray(43.69);
    util.add("arr", arr);
    std::cout << "------------------" << std::endl;
    std::cout << "package json 3: " << util.unformattedData() << std::endl;
    std::vector<RapidJsonUtil> vtObjs;
    RapidJsonUtil obj0;
    obj0.add("int", 345);
    obj0.add("double", 89.77);
    obj0.add("able", true);
    obj0.add("string", "test 00");
    vtObjs.emplace_back(obj0);

    RapidJsonUtil obj1;
    obj1.add("int", 245);
    obj1.add("double", 49.77);
    obj1.add("able", false);
    obj1.add("string", "test 01");
    vtObjs.emplace_back(obj1);

    RapidJsonUtil obj2;
    obj2.add("int", 845);
    obj2.add("double", 59.77);
    obj2.add("able", false);
    obj2.add("string", "test 02");
    vtObjs.emplace_back(obj2);

    util.addObjArray("objs", vtObjs);
    std::cout << "------------------" << std::endl;
    std::cout << "package json 4: " << util.unformattedData() << std::endl;

    return;
}

void testRapidJsonParse()
{
    std::string strJson = R"({"name":"Alice","age":32,"enable":true,"hight":156.78,"data":{"message":"this is message","status":200},"hobbies":["reading","coding","traveling"],"objs":[{"int":12,"ddd":234.56},{"int":24,"ddd":678.56}],"scorse":[23.4,56.7,89.8,45.5]})";
    RapidJsonUtil util(strJson);
    if (util.isJsonOk()) {
        printf("name: %s, age: %d, enable: %d, hight: %f.\r\n"
               , util.value("name").toString().c_str(), util.value("age").toInt()
               , util.value("enable").toBool(), util.value("hight").toDouble());

        printf("nokey: %s.\r\n", util.value("nokey").toString().c_str());
        RapidJsonUtil utildata = util.value("data");
        std::cout << utildata.data() << std::endl << utildata.unformattedData() << std::endl;

        RapidJsonUtil utilhobbies = util.value("hobbies");
        for (int i = 0, cnt = utilhobbies.count(); i < cnt; ++i) {
            printf("item: %d, value: %s.\r\n", i, utilhobbies.at(i).toString().c_str());
        }

        std::cout << utildata.getString("message") << ", " << utildata.getInt("status") << std::endl;
        std::cout << util.getString("objs") << std::endl;

        std::vector<RapidJsonUtil> vtObjs;
        util.getObjArray("objs", vtObjs);
        for (size_t i = 0, size = vtObjs.size(); i < size; ++i) {
            printf("item: %lu, value: %s.\r\n", i, vtObjs[i].unformattedData().c_str());
        }

        std::vector<double> vtDVals;
        util.getDoubleArray("scorse", vtDVals);
        for (size_t i = 0, size = vtDVals.size(); i < size; ++i) {
            printf("item: %lu, value: %f.\r\n", i, vtDVals[i]);
        }
    }

    RapidJsonUtil utiltemp = util;
    std::cout << "temp: " << utiltemp.data() << std::endl;
    utiltemp.deleteKey("name");
    std::cout << "temp delete name key: " << utiltemp.data() << std::endl;

    return;
}

void testRapidJson()
{
    std::cout << "----------testRapidJosnWriter----------" << std::endl;
    //testRapidJosnWriter();
    std::cout << "----------testRapidJosnReader----------" << std::endl;
    //testRapidJosnReader();
    std::cout << "----------testPackgeOrParse----------" << std::endl;
    //testPackgeOrParse();
    std::cout << "----------testRapidJsonPackage----------" << std::endl;
    testRapidJsonPackage();
    std::cout << "----------testRapidJsonParse----------" << std::endl;
    testRapidJsonParse();

    return;
}

// 打印磁盘信息
static void printDiskInfo(const DiskInfo& disk)
{
    printf("[disk info] >>> name: %s, path: %s, model: %s, serial: %s, type: %s, health_status: %s, temperature: %s, total size (KB): %lf, available size (KB): %lf.\r\n"
           , disk.strName.data(), disk.strPath.data(), disk.strModel.data(), disk.strSerial.data()
           , disk.strType.data(), disk.strHealthStatus.data(), disk.strTemperature.data(), disk.dTotalKB, disk.dAvailKB);
    return;
}

void testNetInterfaceInfo()
{
    startNetStateMonitor(20);

    std::this_thread::sleep_for(std::chrono::seconds(30));

    NetInterfaceInfo stInfo;
    getNetInterfaceInfo(stInfo);
    printf(">>> tx_speed: %lf KB/s, rx_speed: %lf KB/s, net cards: %llu, open ports: %llu.\r\n"
           , stInfo.dTxSpeedKBs, stInfo.dRxSpeedKBs, stInfo.vtEthNames.size(), stInfo.vtPortInfos.size());

    std::cout << "Net card: ";
    for (auto& card : stInfo.vtEthNames) {
        std::cout << card << ", ";
    }
    std::cout << std::endl;

    std::cout << "Open port: " << std::endl;
    for (auto& info : stInfo.vtPortInfos) {
        std::cout << info.usPort << ", " << info.strProtocol << ", " << info.srtServiceType << std::endl;
    }

    stopNetStateMonitor();

    return;
}

#define TEST_XML_FILE "test.xml"
void testXmlWrite()
{
    XmlHelper objHelper;
    if (objHelper.createXmlFilePath(TEST_XML_FILE, "RootTag")) {
        // 自动进入根节点
        objHelper.setAttribute("attr1", "this is attr info");
        objHelper.setAttribute("attr2", 134.6);

        objHelper.beginChildElement("Tag1");
        objHelper.setAttribute("attr1", "this is tag1 attr info");
        objHelper.setChildAttribute("SubTag1", "attr1", std::string("strVal"));
        objHelper.setChildAttribute("SubTag1", "attr2", 12.65);
        objHelper.setChildAttribute("SubTag1", "attr3", true);
        objHelper.setChildAttribute("SubTag2", "test", "54");
        objHelper.setChildText("SubTag1", 85.6);
        objHelper.setChildText("SubTag2", "this is info");
        objHelper.setChildText("SubTag3", 78);
        objHelper.endElement();

        objHelper.beginChildElement("Tag2");
        objHelper.setAttribute("attr3", true);
        objHelper.setChildText("info", "this is info");
        objHelper.setChildText("user", 78);
        objHelper.endElement();

        tinyxml2::XMLElement* pElement = objHelper.addChildElement("TagList");
        objHelper.beginElement(pElement);
        objHelper.setChildText("aaa", 456);
        objHelper.setChildAttribute("bbb", "val", 789);
        objHelper.setChildText("bbb", true);
        objHelper.endElement();

        pElement = objHelper.addChildElement("TagList");
        objHelper.beginElement(pElement);
        objHelper.setChildText("aaa", 123);
        objHelper.setChildAttribute("bbb", "val", 36);
        objHelper.setChildText("bbb", false);
        objHelper.endElement();

        objHelper.saveXmlFile();

        COMMONLOG_INFO("write file %s, xml content: %s.", TEST_XML_FILE, objHelper.getXmlContent().c_str());
    }

    return;
}

void testXmlRead()
{
    XmlHelper objHelper;
    if (objHelper.loadXmlFile(TEST_XML_FILE)) {
        //自动进入根节点
        COMMONLOG_INFO("read file %s, xml content: %s.", TEST_XML_FILE, objHelper.getXmlContent().c_str());
        COMMONLOG_INFO("current name: %s, attr1: %s, attr2: %f."
                       , objHelper.currentElemName().data()
                       , objHelper.attribute("attr1").data(), objHelper.doubleAttribute("attr2"));

        objHelper.beginChildElement("Tag1");
        COMMONLOG_INFO("SubTag1, attr1: %s, attr2: %f."
                       , objHelper.childAttribute("SubTag1", "attr1").c_str()
                       , objHelper.childDoubleAttribute("SubTag1", "attr2"));

        //objHelper.setAttribute("SubTag1", "attr3", false);
        objHelper.setChildAttribute("SubTag2", "test", "59");
        COMMONLOG_INFO("SubTag1, attr3: %d.", objHelper.childBoolAttribute("SubTag1", "attr3"));

        COMMONLOG_INFO("%s", "set SubTag1, text is: 106.2.");
        objHelper.setChildText("SubTag1", 106.2);
        COMMONLOG_INFO("set SubTag1, get text is: %f.", objHelper.childDoubleText("SubTag1"));
        objHelper.endElement();

        objHelper.beginChildElement("Tag2");
        objHelper.setChildText("info", "this is info 12132132131");
        objHelper.setChildText("user", 0014);
        COMMONLOG_INFO("%s", "modify Tag2 content.");
        objHelper.endElement();

        std::list<tinyxml2::XMLElement*> lstElements = objHelper.childElements("TagList");
        for (auto iter = lstElements.begin(); iter != lstElements.end(); ++iter)
        {
            objHelper.beginElement(*iter);

            COMMONLOG_INFO("get TagList, aaa text: %d, bbb text: %d attr val: %d.", objHelper.childIntText("aaa")
                           , objHelper.childBoolText("bbb"), objHelper.childIntAttribute("bbb", "val"));

            objHelper.endElement();
        }

        COMMONLOG_INFO("read file %s, modify xml content: %s.", TEST_XML_FILE, objHelper.getXmlContent().c_str());
    } else {
        COMMONLOG_INFO("read xml file: %s failed.", TEST_XML_FILE);
    }

    return;
}

void testConfig()
{
    std::string strContent = "";
    readFile("config.xml", strContent);

    XmlHelper objHelper;
    if (objHelper.parseXmlContent(strContent)) {
        //自动进入根节点
        COMMONLOG_INFO("current name: %s, id: %s, msgId: %d."
                       , objHelper.currentElemName().data()
                       , objHelper.attribute("id").data(), objHelper.intAttribute("msgId"));

        objHelper.beginChildElement("Server");
        COMMONLOG_INFO("Server, ip:port: (%s:%d)."
                       , objHelper.attribute("ip").c_str(), objHelper.intAttribute("port"));
        objHelper.endElement();

        objHelper.beginChildElement("Local");
        COMMONLOG_INFO("Local, ip:port: (%s:%d)."
                       , objHelper.attribute("ip").c_str(), objHelper.intAttribute("port"));
        objHelper.endElement();

        COMMONLOG_INFO("Content: %s.", objHelper.childText("Content").data());

        objHelper.beginChildElement("Content");
        COMMONLOG_INFO("Content: %s, %s.", objHelper.text().data(), objHelper.currentElemText().data());
        objHelper.endElement();
    } else {
        COMMONLOG_INFO("parse xml content: %s failed.", strContent.data());
    }
    return;
}

void testXML()
{
    testXmlWrite();
    testXmlRead();
    testConfig();
    return;
}

int main(int argc, char **argv)
{
    //(void)argc;
    //(void)argv;

    if (2 > argc) {
        return -1;
    }

    if (0 == strcmp(argv[1], "mqtt")) {
        testMqttClient();
    } else if (0 == strcmp(argv[1], "wsclient")) {
        testWebsocketClient();
    } else if (0 == strcmp(argv[1], "http")) {
        testHttp(argc, argv);
    } else if (0 == strcmp(argv[1], "msgqueue")) {
        testMessageQueue(argc, argv);
    } else if (0 == strcmp(argv[1], "fifo")) {
        testFIFO(argc, argv);
    } else if (0 == strcmp(argv[1], "sqlite")) {
        testSqlite3();
    } else if (0 == strcmp(argv[1], "json")) {
        testjson();
    } else if (0 == strcmp(argv[1], "rapidjson")) {
        testRapidJson();
    } else if (0 == strcmp(argv[1], "diskinfo")) {
        std::vector<DiskInfo> vtDiskInfos;
        getDiskInfo(vtDiskInfos);
        for(auto& info : vtDiskInfos) {
            printDiskInfo(info);
        }
    } else if (0 == strcmp(argv[1], "netinfo")) {
        testNetInterfaceInfo();
    } else if (0 == strcmp(argv[1], "xml")) {
        testXML();
    } else {
        std::cout << "input param is error." << std::endl;
    }

    getchar();
    return 0;
}
